/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hextd.server;

import hextd.core.MapLoaderServer;
import hextd.HexTD.GameResult;
import hextd.HexTD.GameState;
import hextd.blackBox.BlackBox;
import hextd.core.ContextHeadless;
import hextd.core.gameloop.GameLoopManager;
import hextd.message.MessageReplayLog;
import hextd.message.MessageReplayLogMP;
import hextd.message.MessageReplayLogSP;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Timer;
import java.util.TimerTask;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author hylke
 */
public class ReplayLogChecker {

	private List<MessageReplayLog> logsToCheck;
	private Map<Integer, Player> playersByUserId;
	private Timer checkTimer;
	private TimerTask checkTask, regTask;
	private URL spPostUrl;
	private URL mpPostUrl;
	private MapLoaderServer mapLoader;
	//
	public static String playerUpdateRegExp = "([0-9-]+),([0-9-]+),([0-9-]+)";
	public static Pattern playerUpdatePattern = Pattern.compile(playerUpdateRegExp);

	public ReplayLogChecker(Map<Integer, Player> playersByUserId, List<MessageReplayLog> logsToCheck, URL spPostUrl, URL mpPostUrl, MapLoaderServer mapLoader, Timer timer) {
		checkTimer = timer;
		this.playersByUserId = playersByUserId;
		this.logsToCheck = logsToCheck;
		this.spPostUrl = spPostUrl;
		this.mpPostUrl = mpPostUrl;
		this.mapLoader = mapLoader;
	}

	public void runCheck() {
		while (logsToCheck.size() > 0) {
			checkLog(logsToCheck.remove(0));
		}
	}

	private void checkLog(MessageReplayLog mrl) {
		ContextHeadless c = new ContextHeadless();
		c.setMapLoader(mapLoader);

		c.setContextUrl(getClass().getResource("/hextd/"));

		BlackBox bbp = new BlackBox(c);
		BlackBox bbr = new BlackBox(c);
		c.setBlackBox(bbr);
		bbp.loadLog(new BufferedReader(new StringReader(mrl.getLog())));
		GameLoopManager gl = new GameLoopManager(c, bbp, bbr);
		c.setGameLoop(gl);
		switch (mrl.getType()) {
			case ReplayLogSP:
				c.setGameState(GameState.checking);
				break;
			case ReplayLogMP:
				c.setGameState(GameState.mpChecking);
				break;
		}
		c.setGameResult(GameResult.active);
		gl.setMaxGameSpeed();
		gl.resetGraceTicks();

		Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
		gl.run();
		Thread.currentThread().setPriority(Thread.NORM_PRIORITY);

		long score = c.getPlayer(0).getScore();
		int level = c.getWave();
		int mapId = -1;
		try {
			mapId = Integer.parseInt(c.getMapLocation());
		} catch (NumberFormatException e) {
		}
		switch (mrl.getType()) {
			case ReplayLogSP:
				MessageReplayLogSP mrlSP = (MessageReplayLogSP) mrl;
				System.out.println("ReplayLogChecker::checkLog: "
						+ mrlSP.getLevel() + "=" + level + " "
						+ mrlSP.getScore() + "=" + score + " "
						+ mrlSP.getMapId() + "=" + mapId);
				if (spPostUrl != null) {
					try {
						URLConnection connection = spPostUrl.openConnection();
						connection.setDoOutput(true);
						OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
						out.write(URLEncoder.encode("score_id", "UTF-8") + "=" + URLEncoder.encode("" + mrl.getReplayId(), "UTF-8") + "&");
						out.write(URLEncoder.encode("level", "UTF-8") + "=" + URLEncoder.encode("" + level, "UTF-8") + "&");
						out.write(URLEncoder.encode("score", "UTF-8") + "=" + URLEncoder.encode("" + score, "UTF-8") + "&");
						out.write(URLEncoder.encode("mapId", "UTF-8") + "=" + URLEncoder.encode("" + mapId, "UTF-8") + "&");

						out.close();
						StringBuilder result = new StringBuilder();
						BufferedReader in = new BufferedReader(
								new InputStreamReader(
								connection.getInputStream()));

						String receivedLine;

						while ((receivedLine = in.readLine()) != null) {
							result.append(receivedLine + "\n");
						}

						in.close();
						int success = result.indexOf("postscore::Success");
						if (success >= 0) {
							System.out.println("ReplayLogChecker::checkLog: Check submitted succesfully");
						} else {
							System.out.println("ReplayLogChecker::checkLog: Failed to submit check!");
							System.out.println(result);
						}
					} catch (IOException ex) {
						System.err.println("ReplayLogChecker::checkLog: IOException submitting check!");
					}
				}
				break;
			case ReplayLogMP:
				MessageReplayLogMP mrlMP = (MessageReplayLogMP) mrl;
				int winner = c.getWinnerId();
				System.out.println("ReplayLogChecker::checkLog: Winner=" + winner + ".");
				if (mpPostUrl != null) {
					try {
						URLConnection connection = mpPostUrl.openConnection();
						connection.setDoOutput(true);
						OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
						out.write(URLEncoder.encode("game_id", "UTF-8") + "=" + URLEncoder.encode("" + mrl.getReplayId(), "UTF-8") + "&");
						out.write(URLEncoder.encode("winner_id", "UTF-8") + "=" + URLEncoder.encode("" + winner, "UTF-8") + "&");
						out.write(URLEncoder.encode("mapId", "UTF-8") + "=" + URLEncoder.encode("" + mapId, "UTF-8") + "&");

						for (int i = 0; i < c.getTotalPlayers(); i++) {
							String varName = "players[" + i + "]";
							String playerId = "" + c.getPlayer(i).getUserId();
							out.write(URLEncoder.encode(varName, "UTF-8") + "=" + URLEncoder.encode(playerId, "UTF-8") + "&");
						}

						out.close();
						StringBuilder result = new StringBuilder();
						BufferedReader in = new BufferedReader(
								new InputStreamReader(
								connection.getInputStream()));

						String receivedLine;

						while ((receivedLine = in.readLine()) != null) {
							result.append(receivedLine + "\n");
							Matcher matcher = playerUpdatePattern.matcher(receivedLine);
							if (matcher.matches()) {
								try {
									int userId = new Integer(URLDecoder.decode(matcher.group(1), "UTF-8"));
									int newRank = new Integer(URLDecoder.decode(matcher.group(2), "UTF-8"));
									int newPlayed = new Integer(URLDecoder.decode(matcher.group(3), "UTF-8"));
									Player p = playersByUserId.get(userId);
									if (p != null) {
										PlayerInfo playerInfo = p.getPlayerInfo();
										playerInfo.rank = newRank;
										playerInfo.games = newPlayed;
									}
									System.err.println("ReplayLogChecker:: checkLog: " + receivedLine);
								} catch (NumberFormatException e) {
									System.err.println("ReplayLogChecker:: checkLog: not a number in line " + receivedLine);
								}
							}

						}

						in.close();
						int success = result.indexOf("postMpGame::Success");
						if (success >= 0) {
							System.out.println("ReplayLogChecker::checkLog: Check submitted succesfully");
						} else {
							System.out.println("ReplayLogChecker::checkLog: Failed to submit check!");
							System.out.println(result);
						}
					} catch (IOException ex) {
						System.err.println("ReplayLogChecker::checkLog: IOException submitting check!");
					}
				}
				break;
		}
	}

	public synchronized void startCheckTimer() {
		if (checkTimer == null) {
			checkTimer = new Timer("ReplayCheckTimer", true);
		}
		if (checkTask == null) {
			checkTask = new TimerTask() {

				@Override
				public void run() {
					runCheck();
				}
			};
			checkTimer.schedule(checkTask, 100, 1000);
		}
	}

	public void stopCheckTimer() {
		this.checkTask.cancel();
		this.checkTask = null;
	}
}
